package htmlparser;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;

import org.apache.commons.httpclient.Cookie;
import org.apache.commons.httpclient.DefaultHttpMethodRetryHandler;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.HttpMethod;
import org.apache.commons.httpclient.HttpState;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
import org.apache.commons.httpclient.URIException;
import org.apache.commons.httpclient.cookie.CookiePolicy;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.params.HttpMethodParams;
import org.apache.commons.httpclient.util.URIUtil;
import org.htmlparser.Parser;
import org.htmlparser.util.ParserException;



public class HtmlParserFactory {
	public static final String USER_AGENT = "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)";
	private ThreadLocal<HttpClient> hc = new ThreadLocal<HttpClient>();
	private ThreadLocal<Cookie[]> cookies = new ThreadLocal<Cookie[]>();

	public HtmlParserFactory() {
		hc.set(new HttpClient((new MultiThreadedHttpConnectionManager())));
		if (LocalProxy.PROXY_USED) {
			hc.get().getHostConfiguration().setProxy(LocalProxy.PROXY_HOST,
					LocalProxy.PROXY_PORT);
			System.setProperty("http.proxyHost", LocalProxy.PROXY_HOST);
			System.setProperty("http.proxyPort", String
					.valueOf(LocalProxy.PROXY_PORT));
		}
	}

	public Parser create(String URLStr) throws ParserException {
		Parser p = new Parser(URLStr);
		return p;
	}



	public Parser createByHttpClientWithCookie(String URLStr)
			throws HttpException, IOException, ParserException {
		Parser p = new Parser();
		GetMethod method = getMethodWithCookie(URLStr);
		if (method != null) {
			try {
				InputStreamReader in = new InputStreamReader(method
						.getResponseBodyAsStream());
				putHtmlInParser(p, in);
			} finally {
				method.releaseConnection();
			}
		}
		return p;
	}

	private GetMethod getMethodWithCookie(String URLStr, Cookie[] cookies) throws HttpException,
			IOException {
		GetMethod method = initMethod(URLStr);

		if (this.cookies.get() == null) {
			saveCookies(cookies);
		}
		HttpState httpState = new HttpState();
		httpState.addCookies(this.cookies.get());
		hc.get().setState(httpState);
		int res = hc.get().executeMethod(method);
		if (res == HttpStatus.SC_OK) {
			return method;
		} else {
			method.releaseConnection();
		}

		return null;
	}

	private GetMethod getMethodWithCookie(String URLStr) throws HttpException,
			IOException {
		GetMethod method = initMethod(URLStr);

		if (cookies.get() == null) {
			saveCookies(URLStr);
		}
		HttpState httpState = new HttpState();
		httpState.addCookies(cookies.get());
		hc.get().setState(httpState);
		int res = hc.get().executeMethod(method);
		if (res == HttpStatus.SC_OK) {
			return method;
		} else {
			method.releaseConnection();
		}

		return null;
	}

	public Parser createByHttpClient(String URLStr) throws HttpException,
			IOException, ParserException {
		HttpMethod method = initMethod(URLStr);
		Parser p = new Parser();
		try {
			int res = hc.get().executeMethod(method);
			if (res == HttpStatus.SC_OK) {
				InputStreamReader in = new InputStreamReader(method
						.getResponseBodyAsStream());
				putHtmlInParser(p, in);
			}
		} finally {
			method.releaseConnection();
		}

		return p;
	}

	public Parser createByFile(String file) throws ParserException, IOException {
		Parser p = new Parser();
		putHtmlInParser(p, new FileReader(file));
		return p;
	}

	protected GetMethod initMethod(String url) {
		String encodeQueryUrl = url;
		try {
			encodeQueryUrl = URIUtil.encodeQuery(url);
		} catch (URIException e) {
		}
		GetMethod method = new GetMethod(encodeQueryUrl);
		method.getParams()
				.setParameter(HttpMethodParams.USER_AGENT, USER_AGENT);
		method.getParams().setCookiePolicy(CookiePolicy.BROWSER_COMPATIBILITY);
		method.getParams().setParameter(HttpMethodParams.RETRY_HANDLER,
				new DefaultHttpMethodRetryHandler(3, false));
		return method;
	}

	protected void proxyHttpClient(HttpClient client, String proxyHost,
			int proxyPort) {
		if (client != null) {
			client.getHostConfiguration().setProxy(proxyHost, proxyPort);
		}
	}

	private void putHtmlInParser(Parser p, Reader in) throws IOException,
			ParserException {
		BufferedReader br = new BufferedReader(in);
		StringBuffer sb = new StringBuffer();
		String s = null;
		while ((s = br.readLine()) != null) {
			s = XMLUtils.removeCommentBlock(s);
			sb.append(s);
		}
		System.out.println(sb.toString());
		p.setInputHTML(sb.toString());
	}

	private void saveCookies(Cookie[] cookies) throws HttpException, IOException {
		this.cookies.set(cookies);
	}
	
	private void saveCookies(String URLStr) throws HttpException, IOException {
		HttpMethod method = initMethod(URLStr);
		int res = hc.get().executeMethod(method);
		if (res == HttpStatus.SC_OK) {
			cookies.set(hc.get().getState().getCookies().clone());
		}
		method.releaseConnection();
	}

	public Parser createByHtml(String html) throws ParserException {
		Parser p = new Parser();
		p.setInputHTML(html);
		return p;
	}
}
